<template>
  <div class="form-config-container">
    <div class="source-tool">
      <div class="item" title="添加数据库连接" @click="addDatasource('jdbc')"><i class="ureport ureport-database"></i></div>
      <div class="item" title="添加SpringBean连接"><i class="ureport ureport-leaf"></i></div>
      <div class="item" title="添加内置数据源连接" @click="addDatasource('buildin')"><i class="ureport ureport-shareconnection"></i></div>
    </div>
    <el-tree :data="treeData" :props="defaultProps" highlight-current default-expand-all>
      <div slot-scope="{ node, data }" class="custom-tree-node" @dblclick="fieldDblclick(node, data)" @mouseover="() => treeNodeOver(node, data)" @mouseout="() => treeNodeOut(node, data)">
        <span class="icon-box">
          <i v-if="data.children" :class="data.icon"></i>
          <i v-else class="el-icon-tickets"></i>
          {{ node.label }}
        </span>
        <span v-show="data==treeNodeOverItem">
          <el-button v-if="node.level<3" type="text" size="mini" :title="node.level===1?'添加数据集':'添加字段'" @click.stop="treeNodeAdd(node, data)">
            <i class="el-icon-circle-plus-outline" />
          </el-button>
          <el-button type="text" size="mini" :title="node.level===1?'编辑数据源':(node.level===2?'编辑数据集':'编辑字段')" @click.stop="treeNodeEdit(node, data)">
            <i class="el-icon-edit-outline" />
          </el-button>
          <el-button type="text" size="mini" :title="node.level===1?'删除数据源':(node.level===2?'删除数据集':'删除字段')" @click.stop="treeNodeRemove(node, data)">
            <i class="el-icon-delete" />
          </el-button>
          <el-button type="text" size="mini" title="刷新" @click.stop="treeNodeRefresh(node, data)">
            <i class="el-icon-yrt-shuaxin" />
          </el-button>
        </span>
      </div>
    </el-tree>

    <!--数据源配置对话框-->
    <data-source-dialog ref="sourceDialog" :visible.sync="showDataSourceDialog" :designer="designer" @on-datasource-success="onDatasourceSuccess">
    </data-source-dialog>

    <!--数据集对话框-->
    <sql-dataset-dialog ref="datasetDialog" :visible.sync="showSqlDatasetDialog" :designer="designer" :current-datasource="currentDatasource" @on-datasource-success="onDatasourceSuccess">
    </sql-dataset-dialog>
  </div>
</template>

<script>
import dataSourceDialog from "./dataSourceDialog";
import sqlDatasetDialog from "./sqlDatasetDialog";
import { undoManager, checkSelection } from "../util/Utils.js";
import Handsontable from "handsontable";
import eventBus from "@/utils/eventBus";

export default {
  components: {
    dataSourceDialog,
    sqlDatasetDialog
  },
  props: {
    designer: {
      type: Object,
      default: () => {
        return {};
      }
    }
  },
  data () {
    return {
      treeData: [],
      defaultProps: {
        children: "children",
        label: "label"
      },
      // 显示数据源配置对话框
      showDataSourceDialog: false,
      // 显示数据集对话框
      showSqlDatasetDialog: false,
      // 显示内建数据集对话框
      showBuildinDatasourceDialog: false,
      // 鼠标滑过Item
      treeNodeOverItem: {},
      // 当前数据源
      currentDatasource: {}
    };
  },
  mounted () {
    this.bindEvent();
  },
  methods: {
    // 事件处理
    bindEvent () {
      // 响应数据加载完毕后事件
      eventBus.$on("bi-data-load-after", ({ designer, context }) => {
        this.onDatasourceSuccess();
      });
    },
    onDatasourceSuccess () {
      const { context } = this.designer;
      const datasources = context.reportDef.datasources || [];
      this.treeData = datasources.map(m => {
        let icon = "";
        if (m.type === "jdbc") {
          icon = "ureport ureport-database";
        } else if (m.type === "spring") {
          icon = "ureport ureport-leaf";
        } else if (m.type === "buildin") {
          icon = "ureport ureport-shareconnection";
        } else {
          icon = "ureport ureport-database";
        }

        // 数据集
        const children = m.datasets.map(dataset => {
          // 构建字段
          const fields = dataset.fields || [];
          const fieldChildren = fields.map(field => {
            return {
              label: field.name,
              icon: "ureport ureport-property"
            };
          });
          return {
            label: dataset.name,
            icon: "ureport ureport-sqlds",
            children: fieldChildren
          };
        });

        // 数据源
        return {
          label: m.name,
          icon: icon,
          children: children
        };
      });
    },
    // 添加数据源
    addDatasource (type) {
      this.showDataSourceDialog = true;
      this.$refs.sourceDialog.init(null, type);
    },
    // tree鼠标进入
    treeNodeOver (node, data) {
      this.treeNodeOverItem = data;
    },
    // tree鼠标移出
    treeNodeOut (node, data) {
      this.treeNodeOverItem = {};
    },
    // 添加字段
    treeNodeAdd (node, data) {
      const { context } = this.designer;
      const datasources = context.reportDef.datasources;
      if (node.level === 1) {
        // 添加数据集
        this.showSqlDatasetDialog = true;
        const datasource = datasources.find(item => item.name === data.label);
        this.currentDatasource = datasource;
        this.$refs.datasetDialog.init(null);
      } else if (node.level === 2) {
        // 添加字段
        const parentData = node.parent.data;
        const datasource = datasources.find(item => item.name === parentData.label);
        const dataset = datasource.datasets.find(item => item.name === data.label);
        // 编辑字段
        this.$prompt("请输入字段名称", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消"
        })
          .then(({ value }) => {
            if (!value) {
              this.$message.error("请输入字段名称");
              return;
            }
            const field = dataset.fields.find(item => item.name === node.label);
            if (field) {
              this.$message.error("字段已存在");
              return;
            }
            dataset.fields.push({
              name: value
            });
            this.onDatasourceSuccess();
          })
          .catch(() => {
            this.$message({
              type: "info",
              message: "取消输入"
            });
          });
      }
    },
    // 编辑字段
    treeNodeEdit (node, data) {
      const { context } = this.designer;
      const datasources = context.reportDef.datasources;
      if (node.level === 1) {
        const datasource = datasources.find(item => item.name === data.label);
        // 编辑数据源
        this.$refs.sourceDialog.init(datasource, datasource.type);
        this.showDataSourceDialog = true;
      } else if (node.level === 2) {
        // 编辑数据集
        const parentData = node.parent.data;
        const datasource = datasources.find(item => item.name === parentData.label);
        const dataset = datasource.datasets.find(item => item.name === data.label);
        this.currentDatasource = datasource;

        this.$refs.datasetDialog.init(dataset);
        this.showSqlDatasetDialog = true;
      } else if (node.level === 3) {
        const rootData = node.parent.parent.data;
        const datasource = datasources.find(item => item.name === rootData.label);
        const parentData = node.parent.data;
        const dataset = datasource.datasets.find(item => item.name === parentData.label);
        // 编辑字段
        this.$prompt("请输入字段名称", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          inputValue: node.label
        })
          .then(({ value }) => {
            if (!value) {
              this.$message.error("请输入字段名称");
              return;
            }
            const field = dataset.fields.find(item => item.name === node.label);
            field.name = value;
            this.onDatasourceSuccess();
          })
          .catch(() => {
            this.$message({
              type: "info",
              message: "取消输入"
            });
          });
      }
    },
    // 删除字段
    treeNodeRemove (node, data) {
      const { context } = this.designer;
      const datasources = context.reportDef.datasources;
      if (node.level === 1) {
        // 删除数据源
        this.$confirm("确定要删除数据源吗？", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消"
        })
          .then(() => {
            const index = datasources.findIndex(item => item.name === node.label);
            datasources.splice(index, 1);
            this.$message.success("删除成功!");
            this.onDatasourceSuccess();
          })
          .catch(() => {
            this.$message({
              type: "info",
              message: "取消删除"
            });
          });
      } else if (node.level === 2) {
        // 删除数据集
        const parentData = node.parent.data;
        const datasource = datasources.find(item => item.name === parentData.label);
        this.$confirm("确定要删除数据集吗？", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消"
        })
          .then(() => {
            const index = datasource.datasets.findIndex(item => item.name === node.label);
            datasource.datasets.splice(index, 1);
            this.$message.success("删除成功!");
            this.onDatasourceSuccess();
          })
          .catch(() => {
            this.$message({
              type: "info",
              message: "取消删除"
            });
          });
      } else if (node.level === 3) {
        // 删除字段
        const rootData = node.parent.parent.data;
        const datasource = datasources.find(item => item.name === rootData.label);
        const parentData = node.parent.data;
        const dataset = datasource.datasets.find(item => item.name === parentData.label);
        this.$confirm("确定要删除字段吗？", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消"
        })
          .then(() => {
            const index = dataset.fields.findIndex(item => item.name === node.label);
            dataset.fields.splice(index, 1);
            this.$message.success("删除成功!");
            this.onDatasourceSuccess();
          })
          .catch(() => {
            this.$message({
              type: "info",
              message: "取消删除"
            });
          });
      }
    },
    // 刷新
    treeNodeRefresh () {
      this.onDatasourceSuccess();
      this.$message.success("刷新成功");
    },
    // 双击字段
    fieldDblclick (node, data) {
      const { context } = this.designer;
      if (node.level !== 3) return; // 只允许字段双击
      if (!checkSelection(context)) {
        return;
      }

      const datasources = context.reportDef.datasources;
      const rootData = node.parent.parent.data;
      const datasource = datasources.find(item => item.name === rootData.label);
      const parentData = node.parent.data;
      const dataset = datasource.datasets.find(item => item.name === parentData.label);
      const field = dataset.fields.find(item => item.name === data.label);

      const hot = context.hot;
      // const cellsMap = context.cellsMap;
      const selected = hot.getSelected()[0];

      const rowIndex = selected[0];
      const colIndex = selected[1];
      let cellDef = context.getCell(rowIndex, colIndex);
      let oldCellDef = Object.assign({}, cellDef);

      if (cellDef.value.type !== "dataset") {
        context.removeCell(cellDef);
        cellDef = {
          value: { type: "dataset", conditions: [] },
          rowNumber: cellDef.rowNumber,
          columnNumber: cellDef.columnNumber,
          cellStyle: cellDef.cellStyle
        };
        context.addCell(cellDef);
      }
      cellDef.expand = "Down";
      let value = cellDef.value;
      value.aggregate = "group";
      value.datasetName = dataset.name;
      value.property = field.name;
      value.order = "none";

      let text = value.datasetName + "." + value.aggregate + "(";
      let prop = value.property;
      text += prop + ")";
      hot.setDataAtCell(rowIndex, colIndex, text);
      context.isModify = true;
      hot.render();
      Handsontable.hooks.run(hot, "afterSelectionEnd", selected[0], selected[1], selected[2], selected[3]);

      undoManager.add({
        redo: function () {
          cellDef = context.getCell(rowIndex, colIndex);
          oldCellDef = Object.assign({}, cellDef);
          if (cellDef.value.type !== "dataset") {
            context.removeCell(cellDef);
            cellDef = {
              value: { type: "dataset", conditions: [] },
              rowNumber: cellDef.rowNumber,
              columnNumber: cellDef.columnNumber,
              cellStyle: cellDef.cellStyle
            };
            context.addCell(cellDef);
          }
          cellDef.expand = "Down";
          value = cellDef.value;
          value.aggregate = "group";
          value.datasetName = dataset.name;
          value.property = field.name;
          value.order = "none";

          text = value.datasetName + "." + value.aggregate + "(";
          prop = value.property;
          text += prop + ")";
          hot.setDataAtCell(rowIndex, colIndex, text);
          context.isModify = true;
          hot.render();
          Handsontable.hooks.run(hot, "afterSelectionEnd", selected[0], selected[1], selected[2], selected[3]);
        },
        undo: function () {
          cellDef = context.getCell(rowIndex, colIndex);
          context.removeCell(cellDef);
          context.addCell(oldCellDef);
          value = oldCellDef.value;
          let text = value.value || "";
          if (value.type === "dataset") {
            text = value.datasetName + "." + value.aggregate + "(";
            const prop = value.property;
            text += prop + ")";
          }
          hot.setDataAtCell(rowIndex, colIndex, text);
          context.isModify = true;
          hot.render();
          Handsontable.hooks.run(hot, "afterSelectionEnd", selected[0], selected[1], selected[2], selected[3]);
        }
      });
    }
  }
};
</script>

<style lang="scss" scoped>
.form-config-container {
  padding-bottom: 20px;
  ::v-deep .el-input-number--medium .el-input-number__decrease,
  ::v-deep .el-input-number--medium .el-input-number__increase {
    width: 28px;
  }
  ::v-deep .el-input-number--medium .el-input__inner {
    padding-left: 10px;
    padding-right: 33px;
  }
  ::v-deep .el-form-item {
    margin-bottom: 0px;
  }

  .source-tool {
    display: flex;
    justify-content: flex-start;
    background: #f8f8f8;
    padding: 2px 5px;
    .item {
      cursor: pointer;
      + .item {
        margin-left: 10px;
      }
    }
  }
  .custom-tree-node {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 14px;
    padding-right: 8px;

    -webkit-touch-callout: none; /*系统默认菜单被禁用*/
    -webkit-user-select: none; /*webkit浏览器*/
    -khtml-user-select: none; /*早期浏览器*/
    -moz-user-select: none; /*火狐*/
    -ms-user-select: none; /*IE10*/
    user-select: none;
  }
}
</style>
